﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Reflection;
using System.Threading;
using System.Configuration;
using FX.CC.Andon.Kanban.KanbanSvcRef;
using System.Media;

namespace FX.CC.Andon.Kanban
{
    static class Program
    {

        public const string res_width_cfg_key = "DisplayWidth";
        public const string res_height_cfg_key = "DisplayHeight";
        const int res_default_width = 800;
        const int res_default_height = 600;

        public const string session_id_key = "SessionID";
        public const string listening_line_key = "LN";
        public const string listening_error_key = "Error";
        public const char split_delimater = ',';

        const int andon_page_size = 5;
        const int task_page_size = 8;

        static Guid sessionID;

        static IList<Guid> lineList;
        static IList<string> errList;
        static IList<KanbanWrapper> previousAndonSet;

        static KanbanDataSvc svc;
        static Thread readTh;
        static SoundPlayer player;

        static frmErrorTips ErrorForm;
        static Action<frmErrorTips, string> actPopErrorMsgForm;
        static frmInvoker invokerForm;
        static frmTaskInfo taskListForm;
        static frmAndonInfo andonListFrom;
        
        static Action<IList<KanbanWrapper>> actUpdateAndonKanban;
        static Action<IList<TaskKanbanWrapper>, bool, string> actUpdateTaskKanban;

        public static bool cursorShown = false;

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            bool firstRun;

            //Create a new mutex using specific mutex name
            Mutex m =new Mutex( false, "FX.CC.Andon.Kanban", out firstRun );

            if( !firstRun ){
                _MsgBox.PopWarning("程序已经运行");
                return;
            }

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            try
            {
#if !DEBUG
                int resWidth =res_default_width, resHeight = res_default_height;

                bool resCfgExists = ConfigurationManager.AppSettings.AllKeys.Contains(res_width_cfg_key);
                if(!resCfgExists){
                    var cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                    cfg.AppSettings.Settings.Add(res_width_cfg_key, res_default_width.ToString());
                    cfg.AppSettings.Settings.Add(res_height_cfg_key, res_default_height.ToString());
                    cfg.Save(ConfigurationSaveMode.Modified);
                }
                else{
                    string widthStr =  ConfigurationManager.AppSettings[res_width_cfg_key];
                    string heightStr = ConfigurationManager.AppSettings[res_height_cfg_key];
                    int.TryParse(widthStr, out resWidth);
                    int.TryParse(heightStr, out resHeight);
                }
                var res = new Resolution();
                res.setResolution(resWidth, resHeight, 60, 32);
#endif
                bool testOK = false;
                using (var frm = new frmConnectionTest())
                {
                    testOK = frm.ShowDialog() == DialogResult.OK;
                }
                if (!testOK) return;

                bool flag = _Upgrade.Upgrade(1);
                if (flag)
                {
                    string upgradeToolLocation =  Application.StartupPath + "\\FX.CC.Andon.UpgradeTool.EXE";
                    System.Diagnostics.Process.Start(upgradeToolLocation, "\"" + Application.ExecutablePath + "\"");
                    return;
                }

                ReadConfig();

                //init player
                player = new SoundPlayer(Application.StartupPath + "\\Alarm.wav");
                player.Load();


                svc = new KanbanDataSvc();
                bool ok = svc.UpdateLoadConfig(sessionID, lineList.ToArray(), errList.ToArray());

                var svrTime = svc.GetServerTime();
                _API.SetLocalTime(svrTime);

                ErrorForm = new frmErrorTips();

                actPopErrorMsgForm = new Action<frmErrorTips, string>((msgForm, msg) =>
                {
                    msgForm.ErrorMsg = msg;
                    msgForm.Show();
                });


                invokerForm = new frmInvoker();

                actUpdateAndonKanban = new Action<IList<KanbanWrapper>>((set) => {
                    if (andonListFrom == null || andonListFrom.IsDisposed)
                    {
                        andonListFrom = new frmAndonInfo();
                        andonListFrom.Show();
                    }
                    else {
                        andonListFrom.Activate();
                    }

                    andonListFrom.SetDataSource(set);
                });

                actUpdateTaskKanban = new Action<IList<TaskKanbanWrapper>, bool, string>((set, play, notice) => {
                    if (taskListForm == null || taskListForm.IsDisposed)
                    {
                        taskListForm = new frmTaskInfo();
                        taskListForm.Show();
                    }
                    else
                    {
                        taskListForm.Activate();
                    }

                    taskListForm.SetDataSource(set, play, notice);
                });

                readTh = new Thread(DoGetData);
                readTh.IsBackground = true;
                readTh.Start();

                Cursor.Hide();

                Application.Run(invokerForm);
            }
            catch (Exception ex)
            {
                _MsgBox.PopError(ex.Message);
            }
            finally
            {
                m.Dispose() ;
            }
        }

        static void ReadConfig() {
            previousAndonSet = new List<KanbanWrapper>();
            string sessionStr = ConfigurationManager.AppSettings[session_id_key];
            string wsStr = ConfigurationManager.AppSettings[listening_line_key];
            string errStr = ConfigurationManager.AppSettings[listening_error_key];

            try
            {
                sessionID = new Guid(sessionStr);
            }
            catch
            {
                sessionID = Guid.NewGuid();
                var cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                cfg.AppSettings.Settings[session_id_key].Value = sessionID.ToString();
                cfg.Save(ConfigurationSaveMode.Modified);
            }

            var wsStrArr = wsStr.Split(split_delimater);
            var errStrArr = errStr.Split(split_delimater);

            lineList = wsStrArr.Select(p => new Guid(p)).ToList();
            errList = errStrArr;
        }

        static void DoGetData()
        {
            Thread.Sleep(3000);
            //IList<KanbanWrapper> andonListEmptySet = new List<KanbanWrapper>();
            IList<TaskKanbanWrapper> tskListEmptySet = new List<TaskKanbanWrapper>();
            while (true)
            {
                try
                {
                    var taskSet = svc.GetTaskListBySession(sessionID, DateTime.Now.Date);
                    var noticeSet = svc.GetNotice();

                    bool show = noticeSet.Length > 0;
                    string noticeStr = string.Empty;
                    if (show)
                    {
                        noticeStr = noticeSet.FirstOrDefault();
                    }

#if DEBUG
                    invokerForm.BeginInvoke(actPopErrorMsgForm, ErrorForm, "获取的数据条数：" + taskSet.Length);
#endif
                    if (taskSet.Length == 0)
                    {
                        invokerForm.Invoke(actUpdateTaskKanban, tskListEmptySet, show, noticeStr);
                        Thread.Sleep(10000);
                        //continue;
                    }
                    else
                    {
                        taskSet = taskSet.OrderByDescending(p => p.EqCode).ToArray();

                        int taskPageCount = taskSet.Length / task_page_size;
                        if (taskSet.Length % task_page_size != 0)
                        {
                            ++taskPageCount;
                        }

                        for (int idx = 0; idx < taskPageCount; idx++)
                        {
                            var tskPagedSet = taskSet.Skip(task_page_size * idx).Take(task_page_size).ToList();
                            tskPagedSet.ForEach(p => p.Rate = ((decimal)p.ConfirmQty / p.PlanQty).ToString("P"));
                            invokerForm.Invoke(actUpdateTaskKanban, tskPagedSet, show, noticeStr);
                            Thread.Sleep(20000);
                        }
                    }

                    //andon info
                    var set = svc.GetEvent(sessionID, DateTime.Now.Date);

                    if (set.Length == 0)
                    {
                        continue;
                    }

                    set = set.OrderByDescending(p => p.StartTime).ToArray();

                    //声音提醒
                    var sameSet = set.Join(previousAndonSet, i => i.EventID, j => j.EventID, (i, j) => i);
                    var deltaSet = set.Except(sameSet).ToList();

                    previousAndonSet = set.ToList();

                    if (deltaSet.Count > 0)
                    {
                        player.Play();
                    }

                    //判断
                    int pageCount = set.Length / andon_page_size;
                    if (set.Length % andon_page_size != 0)
                    {
                        ++pageCount;
                    }

                    for (int idx = 0; idx < pageCount; idx++)
                    {
                        var pagedSet = set.Skip(andon_page_size * idx).Take(andon_page_size).ToList();
                        DateTime curTime = DateTime.Now;
                        pagedSet.ForEach(p =>
                        {
                            decimal totalTime = (decimal)(curTime.Subtract(p.StartTime).TotalMinutes - p.ReduceMin);
                            p.TotalTime = totalTime < 0 ? 0 : totalTime;
                        });
                        invokerForm.Invoke(actUpdateAndonKanban, pagedSet);
                        Thread.Sleep(20000);
                    }
                    
                }
                catch (Exception ex)
                {
                    invokerForm.BeginInvoke(actPopErrorMsgForm, ErrorForm, ex.ToString());
                    Thread.Sleep(20000);
                }
            }
        }
    }

    public static class _MsgBox
    {
        public static DialogResult PopInfo(string content)
        {
            return MessageBox.Show(content, "提示", MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1);
        }

        public static DialogResult PopWarning(string content)
        {
            return MessageBox.Show(content, "警告", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
        }

        public static DialogResult PopError(string content)
        {
            return MessageBox.Show(content, "错误", MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
        }

        public static DialogResult PopQuestion(string content)
        {
            return MessageBox.Show(content, "询问", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
        }
    }
}
